/**
 * Accenture - Servicing Front-end
 */
package sk.lukaskrupa.guess.the.color.core;

import static sk.lukaskrupa.guess.the.color.core.ApplicationConstants.COLOR_REPETITION_STRING;
import static sk.lukaskrupa.guess.the.color.core.ApplicationConstants.DIFFICULTY_PREF_STRING;
import static sk.lukaskrupa.guess.the.color.core.ApplicationConstants.MAX_GUESSES;
import sk.lukaskrupa.guess.the.color.logging.Logging;
import sk.lukaskrupa.guess.the.color.ui.ColorPicker;
import sk.lukaskrupa.guess.the.color.ui.R;
import sk.lukaskrupa.guess.the.color.utils.GuessColorUtil;
import android.content.SharedPreferences;
import android.util.SparseArray;
import android.view.View;
import android.widget.ImageButton;

/**
 * Contains methods that do specific action according to settings selected.
 * 
 * @author Lukas Krupa (lukas0krupa@gmail.com)
 * 
 */
public class GameVariantSpecificActions {

	private static Logging logger = Logging.getLog(GameVariantSpecificActions.class);

	private final SharedPreferences appSettings;

	public GameVariantSpecificActions(SharedPreferences appSettings) {
		this.appSettings = appSettings;
	}

	/**
	 * Generates randomly colors for guessing.
	 * 
	 * @return array of 5 random colors.
	 */
	public SparseArray<ColorEnum> generateRandomColors() {

		// Gets difficulty level
		int numberOfColors = DifficultyEnum.enumForValue(this.appSettings.getInt(DIFFICULTY_PREF_STRING, DifficultyEnum.EASY.getValue()))
				.getNumberOfColors();

		int[] weights = null;
		// Create weights
		if (numberOfColors == 6) {
			weights = new int[]{120, 20, 40, 60, 80, 100};
		} else if (numberOfColors == 8) {
			weights = new int[]{160, 20, 40, 60, 80, 100, 120, 140};

		}

		SparseArray<ColorEnum> result = new SparseArray<ColorEnum>(5);
		ColorEnum newColor = null;

		for (int guessPosition = 1; guessPosition <= MAX_GUESSES; guessPosition++) {

			long randomNumber = Math.round(Math.random() * weights[0]);

			if (randomNumber < weights[1]) {
				newColor = ColorEnum.BLACK;
			} else if (randomNumber < weights[2]) {
				newColor = ColorEnum.BLUE;
			} else if (randomNumber < weights[3]) {
				newColor = ColorEnum.GREEN;
			} else if (randomNumber < weights[4]) {
				newColor = ColorEnum.RED;
			} else if (randomNumber < weights[5]) {
				newColor = ColorEnum.WHITE;
			} else if (weights.length == 6 || randomNumber < weights[6]) {
				newColor = ColorEnum.YELLOW;
			} else if (randomNumber < weights[7]) {
				newColor = ColorEnum.BROWN;
			} else {
				newColor = ColorEnum.PURPLE;
			}

			if (result.indexOfValue(newColor) >= 0) {
				guessPosition--;
				continue;
			}

			result.put(guessPosition, newColor);
		}

		return result;
	}

	/**
	 * Shows colors according to difficulty.
	 * 
	 * @param colorPicker
	 *            to show colors on
	 */
	public void modifyColorPickerAccordingToDifficulty(ColorPicker colorPicker) {
		int numberOfColors = DifficultyEnum.enumForValue(this.appSettings.getInt(DIFFICULTY_PREF_STRING, DifficultyEnum.EASY.getValue()))
				.getNumberOfColors();

		if (numberOfColors == 8) {
			colorPicker.showButton(R.id.popup_button7);
			colorPicker.showButton(R.id.popup_button8);
		} else {
			colorPicker.hideButton(R.id.popup_button7);
			colorPicker.hideButton(R.id.popup_button8);
		}

	}

	/**
	 * Validates match according to difficulty.
	 * 
	 * @return true/false if input is validated
	 */
	public boolean guessMatch(Board board) {

		SparseArray<ColorEnum> result = null;
		switch (DifficultyEnum.enumForValue(this.appSettings.getInt(DIFFICULTY_PREF_STRING, DifficultyEnum.EASY.getValue()))) {
			case VERY_EASY :
			case MEDIUM : {
				result = guessMatchWithExactResult(board);
				break;
			}
			case EASY :
			case HARD : {
				result = guessMatchWithExactResult(board);
				sort(result);
				break;
			}
			default : {
				result = guessMatchWithExactResult(board);
				sort(result);
			}
		}

		boolean playerWon = true;
		for (int columIndex = 1; columIndex <= MAX_GUESSES; columIndex++) {
			playerWon &= ColorEnum.BLACK.equals(result.get(columIndex));
			board.getResults().get(board.getGuessingRow()).put(columIndex, result.get(columIndex));
		}

		return playerWon;
	}

	/**
	 * Check if guess match and game could finish. Return results for each guess
	 * with on position.
	 * 
	 * @param board
	 *            whole
	 * 
	 * @return guess result as Array
	 */
	public SparseArray<ColorEnum> guessMatchWithExactResult(Board board) {

		Board.getLogger(this.getClass()).info("guessMatch", "Hidden colors: " + GuessColorUtil.printSparseArray(board.getHiddenRow()));
		Board.getLogger(this.getClass()).info("guessMatch",
				"Selected colors: " + GuessColorUtil.printSparseArray(board.getGuesses().get(board.getGuessingRow())));

		SparseArray<ColorEnum> result = new SparseArray<ColorEnum>(MAX_GUESSES);

		for (int columnIndex = 1; columnIndex <= MAX_GUESSES; columnIndex++) {

			for (int hiddenIndex = 1; hiddenIndex <= MAX_GUESSES; hiddenIndex++) {

				if (columnIndex == hiddenIndex) {

					if (board.getGuesses().get(board.getGuessingRow()).get(columnIndex).equals(board.getHiddenRow().get(hiddenIndex))) {

						result.put(columnIndex, ColorEnum.BLACK);
						break;
					}

				} else if (board.getGuesses().get(board.getGuessingRow()).get(columnIndex).equals(board.getHiddenRow().get(hiddenIndex))) {

					result.put(columnIndex, ColorEnum.WHITE);
					break;
				}

				result.put(columnIndex, ColorEnum.NONE);
			}
		}

		return result;
	}
	/**
	 * Disabling picked color.
	 * 
	 * @param colorButton
	 *            to be disabled
	 * @param oldColor
	 * @param black
	 */
	public void hideAccordingToSettings(View colorButton, int oldColor, int whatDisableColorToUse) {
		if (this.appSettings.getBoolean(COLOR_REPETITION_STRING, false) == false) {
			((ImageButton) colorButton).setImageDrawable(colorButton.getResources().getDrawable(whatDisableColorToUse));
			((ImageButton) colorButton).setClickable(false);
		}

		// Enabling ColorPicker color, in case setting new color on button where
		// color was chosen
		if (oldColor != 0) {

			switch (oldColor) {
				case R.drawable.black : {
					ImageButton blackButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button1);
					blackButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.black));
					blackButton.setClickable(true);
					break;
				}
				case R.drawable.red : {
					ImageButton redButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button2);
					redButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.red));
					redButton.setClickable(true);
					break;
				}
				case R.drawable.green : {
					ImageButton greenButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button3);
					greenButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.green));
					greenButton.setClickable(true);
					break;
				}
				case R.drawable.white : {
					ImageButton whiteButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button4);
					whiteButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.white));
					whiteButton.setClickable(true);
					break;
				}
				case R.drawable.yellow : {
					ImageButton yellowButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button5);
					yellowButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.yellow));
					yellowButton.setClickable(true);
					break;
				}
				case R.drawable.blue : {
					ImageButton blueButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button6);
					blueButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.blue));
					blueButton.setClickable(true);
					break;
				}
				case R.drawable.brown : {
					ImageButton brownButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button7);
					brownButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.brown));
					brownButton.setClickable(true);
					break;
				}
				case R.drawable.purple : {
					ImageButton purpleButton = (ImageButton) colorButton.getRootView().findViewById(R.id.popup_button8);
					purpleButton.setImageDrawable(colorButton.getResources().getDrawable(R.drawable.purple));
					purpleButton.setClickable(true);
					break;
				}
			}
		}
	}

	/**
	 * Sorts results to have BLACK before WHITE.
	 * 
	 * @param result
	 *            to be sorted
	 */
	private void sort(SparseArray<ColorEnum> result) {

		for (int indexI = 1; indexI < MAX_GUESSES; indexI++) {

			for (int indexJ = 1; indexJ < MAX_GUESSES; indexJ++) {

				if (ColorEnum.NONE.equals(result.get(indexJ))
						|| (ColorEnum.WHITE.equals(result.get(indexJ)) && ColorEnum.BLACK.equals(result.get(indexJ + 1)))) {

					ColorEnum tempColor = result.get(indexJ);
					result.put(indexJ, result.get(indexJ + 1));
					result.put(indexJ + 1, tempColor);

					logger.debug("sort", "Result after: " + GuessColorUtil.printSparseArray(result));
				}
			}
		}
	}
}
